package arithm

import (
	"math/big"
	"testing"
)

func TestRealAddWithInteger(t *testing.T) {
	// Test addition with Integer
	x := Real(3.14)
	y := Integer(5)
	result := x.ADD(y)

	// When adding Real with Integer, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(8.14) // 3.14 + 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealAddWithBigInteger tests Real.ADD method with BigInteger values
func TestRealAddWithBigInteger(t *testing.T) {
	// Test addition with BigInteger
	x := Real(3.14)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.ADD(y)

	// When adding Real with BigInteger, result should be a Real
	f, _ := bigVal.Float64()
	expected := Real(3.14 + f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealAddWithRational tests Real.ADD method with Rational values
func TestRealAddWithRational(t *testing.T) {
	// Test addition with Rational
	x := Real(3.14)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.ADD(y)

	// When adding Real with Rational, result should be a Real
	f, _ := ratVal.Float64()
	expected := Real(3.14 + f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealAddWithReal tests Real.ADD method with Real values
func TestRealAddWithReal(t *testing.T) {
	// Test addition with Real
	x := Real(3.14)
	y := Real(2.86)
	result := x.ADD(y)

	// When adding Real with Real, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(6.0) // 3.14 + 2.86
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealAddWithComplex tests Real.ADD method with Complex values
func TestRealAddWithComplex(t *testing.T) {
	// Test addition with Complex
	x := Real(3.14)
	y := Complex(2 + 3i)
	result := x.ADD(y)

	// When adding Real with Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(5.140000000000001 + 3i) // (3.14 + 0i) + (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealSubWithInteger tests Real.SUB method with Integer values
func TestRealSubWithInteger(t *testing.T) {
	// Test subtraction with Integer
	x := Real(3.14)
	y := Integer(5)
	result := x.SUB(y)

	// When subtracting Integer from Real, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(-1.86) // 3.14 - 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealSubWithBigInteger tests Real.SUB method with BigInteger values
func TestRealSubWithBigInteger(t *testing.T) {
	// Test subtraction with BigInteger
	x := Real(3.14)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.SUB(y)

	// When subtracting BigInteger from Real, result should be a Real
	f, _ := bigVal.Float64()
	expected := Real(3.14 - f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealSubWithRational tests Real.SUB method with Rational values
func TestRealSubWithRational(t *testing.T) {
	// Test subtraction with Rational
	x := Real(3.14)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.SUB(y)

	// When subtracting Rational from Real, result should be a Real
	f, _ := ratVal.Float64()
	expected := Real(3.14 - f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealSubWithReal tests Real.SUB method with Real values
func TestRealSubWithReal(t *testing.T) {
	// Test subtraction with Real
	x := Real(3.14)
	y := Real(2.86)
	result := x.SUB(y)

	// When subtracting Real from Real, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(0.28) // 3.14 - 2.86
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealSubWithComplex tests Real.SUB method with Complex values
func TestRealSubWithComplex(t *testing.T) {
	// Test subtraction with Complex
	x := Real(3.14)
	y := Complex(2 + 3i)
	result := x.SUB(y)

	// When subtracting Complex from Real, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(1.1400000000000001 - 3i) // (3.14 + 0i) - (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealMulWithInteger tests Real.MUL method with Integer values
func TestRealMulWithInteger(t *testing.T) {
	// Test multiplication with Integer
	x := Real(3.14)
	y := Integer(5)
	result := x.MUL(y)

	// When multiplying Real with Integer, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(15.7) // 3.14 * 5
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealMulWithBigInteger tests Real.MUL method with BigInteger values
func TestRealMulWithBigInteger(t *testing.T) {
	// Test multiplication with BigInteger
	x := Real(3.14)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.MUL(y)

	// When multiplying Real with BigInteger, result should be a Real
	f, _ := bigVal.Float64()
	expected := Real(3.14 * f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealMulWithRational tests Real.MUL method with Rational values
func TestRealMulWithRational(t *testing.T) {
	// Test multiplication with Rational
	x := Real(3.14)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.MUL(y)

	// When multiplying Real with Rational, result should be a Real
	f, _ := ratVal.Float64()
	expected := Real(3.14 * f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealMulWithReal tests Real.MUL method with Real values
func TestRealMulWithReal(t *testing.T) {
	// Test multiplication with Real
	x := Real(3.14)
	y := Real(2.0)
	result := x.MUL(y)

	// When multiplying Real with Real, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(6.28) // 3.14 * 2.0
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealMulWithComplex tests Real.MUL method with Complex values
func TestRealMulWithComplex(t *testing.T) {
	// Test multiplication with Complex
	x := Real(3.14)
	y := Complex(2 + 3i)
	result := x.MUL(y)

	// When multiplying Real with Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(3.14 * complex(2, 3)) // 3.14 * (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealDivWithInteger tests Real.DIV method with Integer values
func TestRealDivWithInteger(t *testing.T) {
	// Test division with Integer
	x := Real(3.14)
	y := Integer(2)
	result := x.DIV(y)

	// When dividing Real with Integer, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(1.57) // 3.14 / 2
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealDivWithBigInteger tests Real.DIV method with BigInteger values
func TestRealDivWithBigInteger(t *testing.T) {
	// Test division with BigInteger
	x := Real(3.14)
	bigVal, _ := (new(big.Int)).SetString("12345678901234567890", 10)
	y := (*BigInteger)(bigVal)
	result := x.DIV(y)

	// When dividing Real by BigInteger, result should be a Real
	f, _ := bigVal.Float64()
	expected := Real(3.14 / f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealDivWithRational tests Real.DIV method with Rational values
func TestRealDivWithRational(t *testing.T) {
	// Test division with Rational
	x := Real(3.14)
	ratVal := big.NewRat(5, 2) // 2.5
	y := (*Rational)(ratVal)
	result := x.DIV(y)

	// When dividing Real by Rational, result should be a Real
	f, _ := ratVal.Float64()
	expected := Real(3.14 / f)
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealDivWithReal tests Real.DIV method with Real values

// TestRealDivWithComplex tests Real.DIV method with Complex values
func TestRealDivWithComplex(t *testing.T) {
	// Test division with Complex
	x := Real(3.14)
	y := Complex(2 + 3i)
	result := x.DIV(y)

	// When dividing Real with Complex, result should be a Complex
	if result.Type() != COMPLEX_TYPE {
		t.Errorf("Expected result type %v, got %v", COMPLEX_TYPE, result.Type())
	}

	expected := Complex(3.14 / complex(2, 3)) // 3.14 / (2 + 3i)
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}

// TestRealDivWithReal tests Real.DIV method with Real values
func TestRealDivWithReal(t *testing.T) {
	// Test division with Real
	x := Real(3.14)
	y := Real(2.0)
	result := x.DIV(y)

	// When dividing Real by Real, result should be a Real
	if result.Type() != REAL_TYPE {
		t.Errorf("Expected result type %v, got %v", REAL_TYPE, result.Type())
	}

	expected := Real(1.57) // 3.14 / 2.0
	if result.String() != expected.String() {
		t.Errorf("Expected %v, got %v", expected, result)
	}
}
